# 浏览器渲染原理

  1. HTML代码转化为DOM;
  2. CSS代码转化为CSSOM(CSS Object Model);
  3. 两种树结合,生成一课渲染树Render Tree(包含每个节点的视觉信息,可以想象成是个三维的树);
  4. 生成布局(layout),即将渲染树的所有节点进行平面排布(flow)(可以想象成是三维树排布成平面树,若再次触发这种排布,就称为重排或回流);
  5. 将布局绘制(print)在屏幕上(若再次触发这种绘制,就称为重绘) 注:
  6. 1-3很快,耗时的是4和5,4和5合起来称为“渲染”
  7. 重排一定重绘,重绘不一定重排
  8. dom操作很消耗性能的原因:a.涉及JS引擎和渲染引擎跨线程的通信; b.会频繁触发重排和重绘。

重排和重绘:

  1. 重排:对DOM的修改导致了几何属性的变化(比如:长宽、位置、显隐等),会触发浏览器重新计算、重新排布dom,然后再绘制出来。

    长宽、位置position、显隐display、窗口大小改变触发resize事件、获取style对象上的属性(offsetWidth、offsetHeight、offsetTop等)!!—— 查询style属性会强制发生重排

  2. 重绘:对DOm的修改不会导致几何属性变化(比如:背景色、文字颜色等),无需计算,直接绘制即可。

    color、background、visibility、border-radius、border-color

如何减少重排和重绘?

  1. 避免使用table实现布局,因为细微的改动都可能导致整个页面重排;
  2. 使用visibility:hidden;替换display:none;这样只会重绘不会重排;
  3. 使用transform:translateX替换top等,因为transform是绘制层的属性,不会触发重排;
  4. 避免频繁查询 style对象上的样式属性,例如 document.getElementById('#app').style.offsetTop等,因为查询style属性会强制发生重排;
  5. 设置图层z-index。

# 常见浏览器内核

浏览器内核分为两部分:渲染引擎和JS引擎。一般讲浏览器内核都是指渲染引擎。

浏览器 渲染引擎 JS引擎
IE -> Edge Trident -> EdgeHTML JScript
FireFox Gecko JaegerMonkey
Safari Webkit Nitro
Chrome Webkit -> Blink V8
Opera Presto -> Blink Carakan

Blink 是 Webkit 的分支,所以本质上 Safari、Chrome、Opera 都是 Webkit

js加载会阻塞DOM构建吗?

  1. 不仅会阻塞DOM构建,还有导致CSSOM也阻塞DOM的构建。

css加载会阻塞dom解析吗?
正常情况下,css的加载和解析,与dom的加载和解析同步进行,此时不会阻塞dom的解析,但是有一种情况:浏览器尚未完成CSSOM的下载和构建,而我们却想在此时运行脚本,那么浏览器将延迟脚本执行和DOM构建,直至其完成CSSOM的下载和构建。也就是说,在这种情况下,浏览器会先下载和构建CSSOM,然后再执行JavaScript,最后在继续构建DOM。

减少白屏,应提高css加载速度:

  1. 使用CDN
  2. 进行压缩(webpackgulp等进行打包,或开启gzip压缩);
  3. 合理使用缓存(设置cache-control、expires、e-tag);
  4. 减少请求数(合并资源)。

浏览器如何解析css选择器?
浏览器会『从右往左』解析CSS选择器。
dom树css树渲染生成渲染树,实际上是将css样式附着到对应的dom节点上,而每附着一个样式都要对dom树进行遍历。

以这段代码为例:

.mod-nav h3 span {font-size: 16px;}

对应的dom树结构如下:

若从左向右匹配,即从根节点开始沿每个节点分支进行遍历,结果是每个分支都要被遍历一次; 但是从右向左匹配,可以直接剔除很多分支,可以大大提高遍历效率。

DOMContentLoaded 与 load 区别?

  • load:等待页面所有资源加载完成才会触发,包括css、js、图片等;
  • DOMContentLoaded:等待dom资源加载、解析完成就会触发;
  • DOMContentLoaded总是早于load触发。

asyncdefer的区别?

  • async,加载和渲染后边的html,将与js的加载并行进行,且先加载完成的async优先执行,即执行顺序与加载顺序无关,不确定在DOMContentLoaded之前或之后执行,但一定在load之前执行。适用于不操作domjs文件的加载。
  • defer,加载和渲染后边的html,将与js的加载并行进行,但js的执行要在html解析结束且DOMContentLoaded触发之前,而且执行顺序与加载顺序一致。适用于彼此有依赖关系的js文件的加载。

综上所述,我们得出这样的结论:

  • 浏览器工作流程:构建DOM -> 构建CSSOM -> 构建渲染树 -> 布局 -> 绘制。
  • CSSOM会阻塞渲染,只有当CSSOM构建完毕后才会进入下一个阶段构建渲染树。
  • 通常情况下DOM和CSSOM是并行构建的,但是当浏览器遇到一个不带defer或async属性的script标签时,DOM构建将暂停,如果此时又恰巧浏览器尚未完成CSSOM的下载和构建,由于JavaScript可以修改CSSOM,所以需要等CSSOM构建完毕后再执行JS,最后才继续DOM构建。

参考: https://juejin.im/post/5e143104e51d45414a4715f7

https://fed.taobao.org/blog/taofed/do71ct/performance-composite/?spm=taofed.blogs.blog-list.10.67bd5ac8fHy0LS

https://zhuanlan.zhihu.com/p/47407398

https://juejin.im/post/5a6547d0f265da3e283a1df7

最后更新时间: 3/28/2021, 9:04:52 PM